package net.sf.fc.util;

import java.util.List;

import net.sf.fc.script.gen.copy.Type;
import net.sf.fc.script.gen.options.Filter;
import net.sf.fc.script.gen.options.OptionsScript;
import net.sf.fc.script.gen.options.RenameOptions;
import net.sf.fc.script.gen.options.RenameSuffixOptions;
import net.sf.fc.script.gen.options.RenameType;
import net.sf.fc.script.gen.options.SrcDirOptions;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * Class with static methods that build XML nodes for a CopyScript XML file.
 * @author david
 *
 */
public class CopyScriptXmlUtil {

    public static Node createMapElement(Document owner) {

        return createMapElement(owner, null, null);
    }

    public static Node createMapElement(Document owner, OptionsScript defaultOptions) {

        return createMapElement(owner, null, defaultOptions);
    }

    public static Node createMapElement(Document owner, List<String> texts) {

        return createMapElement(owner, texts, null);
    }

    public static Node createMapElement(Document owner, List<String> texts, OptionsScript defaultOptions) {

        String srcText;
        String dstText;
        if(texts == null) {
            srcText = dstText = null;
        } else {
            int sz = texts.size();
            srcText = sz >= 1 ? texts.get(0) : null;
            dstText = sz >= 2 ? texts.get(1) : null;
        }

        Node mapNode = owner.createElement("map");
        mapNode.appendChild(createSrcElement(owner, srcText, defaultOptions));
        mapNode.appendChild(createDstElement(owner, Type.DIRECTORY, dstText, defaultOptions));
        return mapNode;
    }

    public static Node createSrcElement(Document owner) {

        return createSrcElement(owner, null, null);
    }

    public static Node createSrcElement(Document owner, OptionsScript defaultOptions) {

        return createSrcElement(owner, null, defaultOptions);
    }

    public static Node createSrcElement(Document owner, String text) {

        return createSrcElement(owner, text, null);
    }

    public static Node createSrcElement(Document owner, String text, OptionsScript defaultOptions) {

        Node srcNode = owner.createElement("src");
        srcNode.appendChild(createPathsElement(owner, text, defaultOptions));
        return srcNode;
    }

    public static Node createDstElement(Document owner, Type type) {

        return createDstElement(owner, type, null, null);
    }

    public static Node createDstElement(Document owner, Type type, OptionsScript defaultOptions) {

        return createDstElement(owner, type, null, defaultOptions);
    }

    public static Node createDstElement(Document owner, Type type, String text) {

        return createDstElement(owner, type, text, null);
    }

    public static Node createDstElement(Document owner, Type type, String text, OptionsScript defaultOptions) {

        Node dstNode = owner.createElement("dst");
        dstNode.appendChild(createTypeElement(owner, type));
        dstNode.appendChild(createPathsElement(owner, text, defaultOptions));
        return dstNode;
    }

    public static Node createTypeElement(Document owner, Type type) {

        Node typeNode = owner.createElement("type");
        typeNode.appendChild(owner.createTextNode(type.value()));
        return typeNode;
    }

    public static Node createPathElement(Document owner) {

        return createPathElement(owner, null);
    }

    public static Node createPathElement(Document owner, String text) {

        Node pathNode = owner.createElement("path");
        pathNode.appendChild(owner.createTextNode(text != null ? text : ""));
        return pathNode;
    }

    public static Node createPathsElement(Document owner) {
        return createPathsElement(owner, null, null);
    }

    public static Node createPathsElement(Document owner, OptionsScript defaultOptions) {

        return createPathsElement(owner, null, defaultOptions);
    }

    public static Node createPathsElement(Document owner, String text) {

        return createPathsElement(owner, text, null);
    }

    public static Node createPathsElement(Document owner, String text, OptionsScript defaultOptions) {

        Node pathNode = createPathElement(owner, text);
        Node pathsNode = owner.createElement("paths");
        if(defaultOptions != null) pathsNode.appendChild(createOptionsElement(owner, defaultOptions));
        pathsNode.appendChild(pathNode);

        return pathsNode;
    }

    public static Node createOptionsElement(Document owner, OptionsScript defaultOptions) {

        Node optionsNode = owner.createElement("options");

        optionsNode.appendChild(createRenameOptions(owner, defaultOptions.getRenameOptions()));
        optionsNode.appendChild(createSrcDirOptions(owner, defaultOptions.getSrcDirOptions()));

        optionsNode.appendChild(createBooleanElement(owner, defaultOptions.isCopyAttributes(), "copyAttributes"));
        optionsNode.appendChild(createBooleanElement(owner, defaultOptions.isFollowLinks(), "followLinks"));

        return optionsNode;
    }

    private static Node createRenameOptions(Document owner, RenameOptions renameOptions) {

        Node renameOptionsNode = owner.createElement("renameOptions");
        renameOptionsNode.appendChild(createRenameType(owner, renameOptions.getRenameType()));
        renameOptionsNode.appendChild(createRenameSuffixOptions(owner, renameOptions.getRenameSuffixOptions()));

        renameOptionsNode.appendChild(createBooleanElement(owner, renameOptions.isUpdate(), "update"));
        renameOptionsNode.appendChild(createBooleanElement(owner, renameOptions.isPromptBeforeOverwrite(), "promptBeforeOverwrite"));
        renameOptionsNode.appendChild(createBooleanElement(owner, renameOptions.isBuildRestoreScript(), "buildRestoreScript"));

        return renameOptionsNode;
    }

    private static Node createRenameType(Document owner, RenameType renameType) {
        Node renameTypeNode = owner.createElement("renameType");
        renameTypeNode.appendChild(owner.createTextNode(renameType.value()));

        return renameTypeNode;
    }

    private static Node createRenameSuffixOptions(Document owner, RenameSuffixOptions rnmSfxOptions) {
        Node rnSfxNode = owner.createElement("renameSuffixOptions");

        Node child = owner.createElement("format");
        child.appendChild(owner.createTextNode(rnmSfxOptions.getFormat()));
        rnSfxNode.appendChild(child);

        child = owner.createElement("useGMT");
        child.appendChild(owner.createTextNode(Boolean.valueOf(rnmSfxOptions.isUseGMT()).toString()));
        rnSfxNode.appendChild(child);

        return rnSfxNode;
    }

    private static Node createSrcDirOptions(Document owner, SrcDirOptions srcDirOptions) {
        Node srcDirNode = owner.createElement("srcDirOptions");
        srcDirNode.appendChild(createFilterOptions(owner, srcDirOptions.getFileCopyFilter(), "fileCopyFilter"));
        srcDirNode.appendChild(createFilterOptions(owner, srcDirOptions.getDirCopyFilter(), "dirCopyFilter"));
        srcDirNode.appendChild(createFilterOptions(owner, srcDirOptions.getMergeFilter(), "mergeFilter"));
        srcDirNode.appendChild(createFilterOptions(owner, srcDirOptions.getFlattenFilter(), "flattenFilter"));

        srcDirNode.appendChild(createIntElement(owner, srcDirOptions.getMaxCopyLevel(), "maxCopyLevel"));
        srcDirNode.appendChild(createIntElement(owner, srcDirOptions.getMaxMergeLevel(), "maxMergeLevel"));
        srcDirNode.appendChild(createIntElement(owner, srcDirOptions.getMaxFlattenLevel(), "maxFlattenLevel"));

        return srcDirNode;
    }

    private static Node createFilterOptions(Document owner, Filter filter, String elementName) {
        Node filterNode = owner.createElement(elementName);

        Node child = owner.createElement("value");
        child.appendChild(owner.createTextNode(filter.getValue()));
        filterNode.appendChild(child);

        filterNode.appendChild(createBooleanElement(owner, filter.isCaseSensitive(), "caseSensitive"));
        filterNode.appendChild(createBooleanElement(owner, filter.isRegularExpression(), "regularExpression"));
        filterNode.appendChild(createBooleanElement(owner, filter.isExclusive(), "exclusive"));

        return filterNode;
    }

    private static Node createBooleanElement(Document owner, boolean value, String elementName) {
        Node node = owner.createElement(elementName);
        node.appendChild(owner.createTextNode(Boolean.valueOf(value).toString()));

        return node;
    }

    private static Node createIntElement(Document owner, int value, String elementName) {
        Node node = owner.createElement(elementName);
        node.appendChild(owner.createTextNode(Integer.valueOf(value).toString()));

        return node;
    }


}
